package com.gisquest.cpu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

/**
 * <p>
 *
 * </p>
 * @author liudl
 * @date 2022/9/15
 */
@SpringBootApplication
@EnableConfigurationProperties({ResourseUsageConfig.class})
public class EcsCpuUsageApplication {

    public static void main(String[] args) {
        SpringApplication.run(EcsCpuUsageApplication.class, args);
        memoryInit();
        cpuControl2();
        //cpuControl3();
    }

    /**
     * 内存分配
     */
    private static void memoryInit() {
        int memorysize = GlobalVariable.usageConfig.getMemorysize();
        if (memorysize < 1) {
            return;
        }
        //假定程序跑起来的固定内存占用为50M
        //int占用4字节
        long byteLength = (long) (memorysize - 50) * 1024 * 1024 / 4;
        if (byteLength < 0) {
            return;
        }
        //2^30=1024M
        int maxLength = 1073741824;
        int arrCount = (int) (byteLength / maxLength + 1);
        //取余另占用一个数组
        long residue = byteLength % maxLength;
        System.out.println("填充内存数组个数：" + arrCount);

        ThreadPoolExecutor  threadPool = new ThreadPoolExecutor(
                arrCount,
                arrCount,
                100,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(arrCount),
                new MyThreadFactory("跑内存线程"),
                new ThreadPoolExecutor.DiscardPolicy());

        for (long c = 1; c <= arrCount; c++) {
            //每个数组占用maxLength
            if (c < arrCount) {
                int[] arr = new int[maxLength];
                System.out.println("arr" + c + "的长度" + arr.length);
                threadPool.execute(() -> {
                    for (int i = 0; i < arr.length; i++) {
                        arr[i] = i;
                    }
                });
            }
            //不足maxLength的另占用一个数组
            else {
                int[] arr = new int[(int)residue];
                System.out.println("arr" + c + "的长度" + arr.length);
                threadPool.execute(() -> {
                    for (int i = 0; i < arr.length; i++) {
                        arr[i] = i;
                    }
                });
            }
        }
    }

    /**
     * 控制比率
     */
    private static void cpuControl2() {
        int busyTime = GlobalVariable.usageConfig.getCpuper();
        if (busyTime < 1) {
            busyTime = 1;
        }
        if (busyTime > 95) {
            busyTime = 95;
        }
        int idleTime = 100 - busyTime;
        AtomicLong startTime = new AtomicLong();
        int core = Runtime.getRuntime().availableProcessors();

        ThreadPoolExecutor  threadPool = new ThreadPoolExecutor(
                core,
                core,
                100,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(core),
                new MyThreadFactory("跑CPU线程"),
                new ThreadPoolExecutor.DiscardPolicy());

        for (int i = 0; i < core; i++) {
            int finalBusyTime = busyTime;
            threadPool.execute(() -> {
                while (true) {
                    // busy loop
                    startTime.set(System.currentTimeMillis());
                    // idle loop
                    while ((System.currentTimeMillis() - startTime.get()) <= finalBusyTime) ;
                    try {
                        Thread.sleep(idleTime);
                    } catch (InterruptedException e) {
                        System.out.println(e);
                    }
                }
            });
        }

    }

    /**
     * 正选曲线
     */
    private static void cpuControl3() {
        // 角度的分割
        final double SPLIT = 0.01;
        // 2PI分割的次数，也就是2/0.01个，正好是一周
        final int COUNT = (int) (2 / SPLIT);
        final double PI = Math.PI;
        // 时间间隔
        final int INTERVAL = 200;
        long[] busySpan = new long[COUNT];
        long[] idleSpan = new long[COUNT];
        int half = INTERVAL / 2;
        double radian = 0.0;
        for (int i = 0; i < COUNT; i++) {
            busySpan[i] = (long) (half + (Math.sin(PI * radian) * half));
            idleSpan[i] = INTERVAL - busySpan[i];
            radian += SPLIT;
        }
        long startTime = 0;
        int j = 0;
        while (true) {
            j = j % COUNT;
            startTime = System.currentTimeMillis();
            while (System.currentTimeMillis() - startTime < busySpan[j]) ;
            try {
                Thread.sleep(idleSpan[j]);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            j++;
        }
    }
}
